﻿using log4net;
using log4net.Repository;
using log4net.Config;
using log4net.Core;
using System.Collections.Concurrent;
using System.IO;
using System;
using System.Collections.Generic;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using log4net.Util;

namespace Common
{
    /// <summary>
    /// 日志工具类
    /// </summary>
    public static class LogHelper
    {
        /// <summary>
        /// 日志对象
        /// </summary>
        private static IDictionary<string, ILog> Logs = new ConcurrentDictionary<string, ILog>();

        /// <summary>
        /// 日志存储路径
        /// </summary>
        public static string RootPath = Path.Combine(WorkPath.ExecPath, "logs");

        /// <summary>
        /// 日志级别  Highest: OFF->FATAL->RROR->WARN->INFO->DEBUG->ALL :Lowest
        /// </summary>
        public static Level RootLevel = Level.Info;

        /// <summary>
        /// 日志级别  Highest: OFF->FATAL->RROR->WARN->INFO->DEBUG->ALL :Lowest
        /// </summary>
        public static String RootLevelString = String.Empty;

        /// <summary>
        /// 日志级别  Highest: OFF->FATAL->RROR->WARN->INFO->DEBUG->ALL :Lowest
        /// </summary>
        public static ConcurrentDictionary<String, Level> LevelMap = new(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// 最大的文件大小。可以使用"KB", "MB" 或 "GB"为 MaxFileSize 作为后缀限定大小。默认的文件大小是10MB。
        /// </summary>
        public static String MaximumFileSize = "10MB";

        /// <summary>
        /// 文件数量
        /// </summary>
        public static Int32 MaxSizeRollBackups = 10;

        /// <summary>
        /// 日志内容输出格式
        /// </summary>
        public static String RootPatternLayout = "%date [%thread] %-5level %logger- %message%newline";

        /// <summary>
        /// 写入日志 Info
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mark"></param>
        public static void Info(this string value, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsInfoEnabled)
            {
                loger.Info(value);
            }
        }

        /// <summary>
        /// 写入日志 Info
        /// </summary>
        /// <param name="value"></param>
        /// <param name="exception"></param>
        /// <param name="mark"></param>
        public static void Info(this string value, Exception exception, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsInfoEnabled)
            {
                loger.Info(value, exception);
            }
        }

        /// <summary>
        /// 写入日志 Debug
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mark"></param>
        public static void Debug(this string value, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsDebugEnabled)
            {
                loger.Debug(value);
            }
        }

        /// <summary>
        /// 写入日志 Debug
        /// </summary>
        /// <param name="value"></param>
        /// <param name="exception"></param>
        /// <param name="mark"></param>
        public static void Debug(this string value, Exception exception, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsDebugEnabled)
            {
                loger.Debug(value, exception);
            }
        }

        /// <summary>
        /// 写入日志 Error
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mark"></param>
        public static void Error(this string value, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsErrorEnabled)
            {
                loger.Error(value);
            }
        }

        /// <summary>
        /// 写入日志 Error
        /// </summary>
        /// <param name="value"></param>
        /// <param name="exception"></param>
        /// <param name="mark"></param>
        public static void Error(this string value, Exception exception, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsErrorEnabled)
            {
                loger.Error(value, exception);
            }
        }

        /// <summary>
        /// 写入日志 Fatal
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mark"></param>
        public static void Fatal(this string value, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsFatalEnabled)
            {
                loger.Fatal(value);
            }
        }

        /// <summary>
        /// 写入日志 Fatal
        /// </summary>
        /// <param name="value"></param>
        /// <param name="exception"></param>
        /// <param name="mark"></param>
        public static void Fatal(this string value, Exception exception, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsFatalEnabled)
            {
                loger.Fatal(value, exception);
            }
        }

        /// <summary>
        /// 写入日志 Warn
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mark"></param>
        public static void Warn(this string value, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsWarnEnabled)
            {
                loger.Warn(value);
            }
        }

        /// <summary>
        /// 写入日志 Warn
        /// </summary>
        /// <param name="value"></param>
        /// <param name="exception"></param>
        /// <param name="mark"></param>
        public static void Warn(this string value, Exception exception, string mark = "")
        {
            var loger = GetLog(mark);
            if (loger.IsWarnEnabled)
            {
                loger.Warn(value, exception);
            }
        }

        /// <summary>
        /// 写入日志 
        /// </summary>
        /// <param name="mark"></param>
        private static ILog GetLog(string mark = "")
        {
            // \ / : * ? " < > | 
            mark = mark.Replace(":", ".").Replace("*", ".").Replace("?", ".").Replace("\"", ".").Replace("<", ".").Replace(">", ".").Replace("|", ".");
            String TipMark = mark.ToLowerInvariant();
            if (!Logs.ContainsKey(TipMark))
            {
                //创建滚动日志附加器
                RollingFileAppender rollingFileAppender = new RollingFileAppender();
                rollingFileAppender.Name = "rollingFileAppender_" + mark;//名称
                rollingFileAppender.File = Path.Combine(RootPath, mark) + "/";//日志存储根
                rollingFileAppender.MaxSizeRollBackups = MaxSizeRollBackups;//最大文件数量
                rollingFileAppender.MaximumFileSize = MaximumFileSize;//最大文件大小
                rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Composite;//文件滚动模式
                rollingFileAppender.DatePattern = "yyyyMMdd'.log'";//文件名格式
                rollingFileAppender.AppendToFile = true;//追加到文件
                rollingFileAppender.StaticLogFileName = false;//静态日志文件名
                rollingFileAppender.Layout = new PatternLayout(RootPatternLayout);//日志格式
                rollingFileAppender.LockingModel = new FileAppender.MinimalLock();//文件锁模式
                rollingFileAppender.ActivateOptions();

                //创建日志仓库
                Hierarchy loggerRepository = (Hierarchy)LogManager.CreateRepository("repository_" + mark);
                //从枚举中选取日志级别
                Level _Level = RootLevel;//默认的日志级别
                if (LevelMap != null && !LevelMap.IsEmpty && LevelMap.TryGetValue(mark, out Level value))//模块可以单独配置的日志级别
                {
                    _Level = value;
                }
                else if (!String.IsNullOrWhiteSpace(RootLevelString))//模块统一的日志级别
                {
                    _Level = loggerRepository.LevelMap[RootLevelString];
                }
                loggerRepository.Root.Level = _Level;
                loggerRepository.Root.AddAppender(rollingFileAppender);//滚动日志
                loggerRepository.Root.AddAppender(GetConsoleAppender());//命令行
                loggerRepository.Root.AddAppender(GetTraceAppender());//控制台
                loggerRepository.Configured = true;
                //BasicConfigurator.Configure(loggerRepository);

                //创建并缓存日志操作实例
                Logs.Add(TipMark, LogManager.GetLogger(loggerRepository.Name, mark));
            }

            ILog log = Logs[TipMark];
            return log;
        }

        /// <summary>
        /// 命令行
        /// </summary>
        static ConsoleAppender _ConsoleAppender;
        private static ConsoleAppender GetConsoleAppender()
        {
            if (_ConsoleAppender == null)
            {
                _ConsoleAppender = new ConsoleAppender();
                _ConsoleAppender.Layout = new PatternLayout(RootPatternLayout);
            }
            return _ConsoleAppender;
        }

        /// <summary>
        /// 控制台
        /// </summary>
        static TraceAppender _TraceAppender;
        private static TraceAppender GetTraceAppender()
        {
            if (_TraceAppender == null)
            {
                _TraceAppender = new TraceAppender();
                _TraceAppender.Layout = new PatternLayout(RootPatternLayout);
            }
            return _TraceAppender;
        }
    }
}
